跳到主要内容

CSS 继承与优先级的概念

!important 声明

标记了 !important 的声明会被当作更高优先级的来源,因此总体的优先级按照由高到低

排列如下所示:

  1. 作者的 !important
  2. 作者
  3. 用户代理

层叠独立地解决了网页中每个元素的样式属性的冲突。例如,如果给段落设置加粗的字体,用户代理的上下外边距样式仍然会生效(除非被明确覆盖)。

但是它虽然可能 !important 解决了眼前的问题,但是会在以后带来更多问题。一旦给很多声明加上 !important,要覆盖已设置为 !important 的声明时,该怎么做呢?当给一些声明加上 !important 时,就会先比较来源,再使用常规的优先级规则。最终会让一切回到起点:一旦引入一个 !important,就会带来更多的 !important

因此尽量使用更高优先级的选择器来覆盖样式,而不是使用 !important

选择器优先级

第一个选择器的优先级高于第二个选择器。因为不同类型的选择器有不同的优先级。比如,ID 选择器比类选择器优先级更高。同理,类选择器的优先级比标签选择器(也称类型选择器)更高。

优先级的准确规则如下:

  • 如果选择器的 ID 数量更多,则它会胜出(即它更明确)。
  • 如果 ID 数量一致,那么拥有最多类的选择器胜出。
  • 如果以上两次比较都一致,那么拥有最多标签名的选择器胜出。

如果要覆盖一个 ID 选择器的样式,就必须要用另一个 ID 选择器,而 ID 是唯一的,所以尽量不要用 ID 属性,不过可以用 !important 去覆盖样式。

下面介绍一下 优先级标记 的概念,一个常用的表示优先级的方式是用数值形式来标记,通常用逗号隔开每个数。比如,“1,2,3” 表示选择器由 1 个 ID、2 个类、3 个标签组成。优先级最高的 ID 列为第一位,紧接着是类,最后是标签。

例如:

  • 选择器 #page-header #page-title 有 2 个 ID,没有类,也没有标签,它的优先级可以用 “2,0,0” 表示。
  • 选择器 ul li 有 2 个标签,没有 ID,也没有类名,它的优先级可以用“0,0,2”表示。

如下表所示:

现在通过比较数值就能决定哪个选择器优先级更高(更明确)。“1,0,0” 的优先级高于 “0,2,2” 甚至 “0,10,0”(尽管我不推荐写一个长达 10 个类名的选择器),因为第一个数(ID)有最高优先级。

有时,人们还会用 4 个数的标记,其中将最重要的位置用 0 或 1 来表示,代表一个声明是否是用行内样式添加的。

此时,行内样式 的优先级为 “1,0,0,0”。它会覆盖通过选择器添加的样式,比如优先级为 “0,1,2,0”(1 个 ID 和 2 个类)的选择器。

综上,开发的时候应该尽可能的使用优先级低的样式,这样当需要覆盖一些样式时,才能有选择空间。

继承

如果一个元素的某个属性没有层叠值,则可能会继承某个祖先元素的值。比如通常会给 <body> 元素加上 font-family,里面的所有后代元素都会继承这个字体,就不必给页面的每个元素明确指定字体了。下图展示了继承是如何顺着 DOM 树向下传递的。

但不是所有的属性都能被继承。默认情况下,只有特定的一些属性能被继承,通常是我们希望被继承的那些。它们主要是跟文本相关的属性:

color、font、font-family、font-size、
font-weight、font-variant、font-style、line-height、letter-spacing、text-align、
text-indent、text-transform、white-space 以及 word-spacing。

还有一些其他的属性也可以被继承,比如:

  • 列表属性:list-style、list-style-type、list-style-position 以及 list-style-image;
  • 表格的边框属性 border-collapse 和 border-spacing 也能被继承。

注意,这些属性控制的是表格的边框行为,而不是常用于指定非表格元素边框的属性。(恐怕没人希望将一个 <div> 的边框传递到每一个后代元素。)以上为不完全枚举,但是已经很详尽了。

源码顺序

层叠的第三步,也是最后一步,是源码顺序。如果两个声明的来源和优先级相同,其中一个声明在样式表中出现较晚,或者位于页面较晚引入的样式表中,则该声明胜出

也就是说,可以通过控制源码顺序,来给特殊链接添加样式。如果两个冲突选择器的优先级相同,则出现得较晚的那个胜出。

在这个方法里,选择器优先级相同。源码顺序决定了哪个声明作用于特殊链接,最终产生了橘黄色的特殊按钮。

开发者工具

使用开发者工具能够看到哪些元素应用了哪些样式规则,以及为什么应用这些规则。层叠和继承都是抽象的概念,使用开发者工具是最好的追踪方式。在一个页面元素上点击鼠标右键,选择弹出菜单上的检查元素,就能打开开发者工具,示例如下所示。

特殊值 inherit 和 initial

有两个特殊值可以赋给任意属性,用于控制层叠:inherit 和 initial。

提示

上面继承那一节也描述了不是所有的属性都会继承自父节点,所以得使用下面的这两个关键字来实现继承父亲其它属性的效果

inherit 继承

有时,我们想用继承代替一个层叠值。这时候可以用 inherit 关键字。可以用它来覆盖另一个值,这样该元素就会继承其父元素的值。

假设我们要给网页加上一个浅灰色的页脚。在页脚上有一些链接,但我们不希望这些链接太显眼,因为页脚不是网页的重点。因此要将页脚的链接变成深灰色

<footer class="footer">
&copy; 2016 Wombat Coffee Roasters &mdash;
<a href="/terms-of-use">Terms of use</a>
</footer>

第三个规则集覆盖了蓝色的链接色,让页脚链接的层叠值为 inherit。因此,它继承了父元素 <footer> 的颜色。

这么做的好处是,如果页脚发生任何样式改变的话(比如修改第二个规则集,或者被别的样式覆盖),页脚链接的颜色就会跟着页脚其他内容一起改变。比如,当页脚文本变为更深的灰色时,其中的链接也会跟着改变。

initial 撤销样式

有时,你需要撤销作用于某个元素的样式。这可以用 initial 关键字来实现。每一个 CSS 属性都有初始(默认)值。如果将 initial 值赋给某个属性,那么就会有效地将其重置为默认 值,这种操作相当于硬复位了该值。下图展示了给页脚链接赋以 initial 而不是 inherit 时的效果。

因为在大多数浏览器中,黑色是 color 属性的初始值,所以 color: initial 等价于 color: black。

.footer a {
color: initial;
text-decoration: underline;
}

这么做的好处是不需要思考太多。如果想删除一个元素的边框,设置 border: initial 即可。如果想让一个元素恢复到默认宽度,设置 width: initial 即可。

References

  • 《深入解析 CSS》